home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1999 #2 / Amiga Plus CD - 1999 - No. 2.iso / System-Boost / Workbench / ToolManager / Source / Library / dock.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  31KB  |  1,171 lines

  1. /*
  2.  * dock.c  V3.1
  3.  *
  4.  * ToolManager Objects Dock class
  5.  *
  6.  * Copyright (C) 1990-98 Stefan Becker
  7.  *
  8.  * This source code is for educational purposes only. You may study it
  9.  * and copy ideas or algorithms from it for your own projects. It is
  10.  * not allowed to use any of the source codes (in full or in parts)
  11.  * in other programs. Especially it is not allowed to create variants
  12.  * of ToolManager or ToolManager-like programs from this source code.
  13.  *
  14.  */
  15.  
  16. #include "toolmanager.h"
  17.  
  18. /* Menu IDs */
  19. #define MENU_CLOSE 0
  20. #define MENU_PREFS 1
  21. #define MENU_QUIT  2
  22.  
  23. /* Local data */
  24. #define PROPCHUNKS 3
  25. static const ULONG PropChunkTable[2 * PROPCHUNKS] = {
  26.  ID_TMDO, ID_FONT,
  27.  ID_TMDO, ID_HKEY,
  28.  ID_TMDO, ID_PSCR
  29. };
  30. static const struct TagItem TagsToFlags[] = {
  31.  TMOP_Activated, DATA_DOCKF_ACTIVATED,
  32.  TMOP_Centered,  DATA_DOCKF_CENTERED,
  33.  TMOP_FrontMost, DATA_DOCKF_FRONTMOST,
  34.  TMOP_Menu,      DATA_DOCKF_MENU,
  35.  TMOP_PopUp,     DATA_DOCKF_POPUP,
  36.  TMOP_Text,      DATA_DOCKF_TEXT,
  37.  TMOP_Backdrop,  DATA_DOCKF_BACKDROP,
  38.  TMOP_Sticky,    DATA_DOCKF_STICKY,
  39.  TMOP_Images,    DATA_DOCKF_IMAGES,
  40.  TMOP_Border,    DATA_DOCKF_BORDER,
  41.  TAG_DONE
  42. };
  43. static const struct TagItem CreateMenusTags[] = {
  44.  GTMN_FullMenu, TRUE,
  45.  TAG_DONE
  46. };
  47. static const struct TagItem LayoutMenusTags[] = {
  48.  GTMN_NewLookMenus, TRUE,
  49.  TAG_DONE
  50. };
  51. static struct NewMenu DockMenu[]              = {
  52.  {NM_TITLE, NULL, NULL, 0, ~0, NULL},
  53.   {NM_ITEM, NULL, NULL, 0, ~0, (APTR) MENU_CLOSE},
  54.   {NM_ITEM, NULL, NULL, 0, ~0, (APTR) MENU_PREFS},
  55.   {NM_ITEM, NULL, NULL, 0, ~0, (APTR) MENU_QUIT},
  56.  {NM_END}
  57. };
  58. static ULONG           GadToolsLockCount      = 0;
  59. static struct Library *GadToolsBase           = NULL;
  60.  
  61. struct DockEntry {
  62.  struct MinNode        de_Node;
  63.  struct DockEntryChunk de_Data;
  64. };
  65.  
  66. /* Dock class instance data */
  67. struct DockClassData {
  68.  ULONG            dcd_Flags;
  69.  ULONG            dcd_LeftEdge;
  70.  ULONG            dcd_TopEdge;
  71.  ULONG            dcd_Columns;
  72.  struct TextAttr  dcd_TextAttr;
  73.  char            *dcd_PubScreen;
  74.  CxObj           *dcd_HotKey;
  75.  struct MinList   dcd_Entries;   /* entries: struct DockEntry */
  76.  Object          *dcd_Gadget;
  77.  struct TextFont *dcd_Font;
  78.  struct Window   *dcd_Window;
  79.  APTR             dcd_VisualInfo;
  80.  struct Menu     *dcd_Menu;
  81.  void            *dcd_AppWindow;
  82.  ULONG            dcd_Seconds;
  83.  ULONG            dcd_Micros;
  84. };
  85. #define TYPED_INST_DATA(cl, o) ((struct DockClassData *) INST_DATA((cl), (o)))
  86.  
  87. /* Flags for strings allocated in IFF parsing */
  88. #define IFFF_FONTNAME    0x80000000 /* dcd_TextAttr.ta_Name */
  89. #define IFFF_PUBSCREEN   0x40000000 /* dcd_PubScreen        */
  90.  
  91. /* Internal state flags */
  92. #define DOCKF_DEFERCLOSE 0x20000000 /* Defer close while dock is active    */
  93. #define DOCKF_REOPEN     0x10000000 /* Open dock when screen is open again */
  94.  
  95. /* Open gadtools.library */
  96. static BOOL LockGadTools(void)
  97. {
  98.  BOOL rc;
  99.  
  100.  /* GadTools already opened or can we open it? */
  101.  if (rc = (GadToolsBase != NULL) ||
  102.           (GadToolsBase = OpenLibrary("gadtools.library", 39)))
  103.  
  104.   /* Increment lock counter */
  105.   GadToolsLockCount++;
  106.  
  107.  return(rc);
  108. }
  109.  
  110. /* Close gadtools.library */
  111. static void ReleaseGadTools(void)
  112. {
  113.  /* Decrement lock counter */
  114.  if (--GadToolsLockCount == 0) {
  115.  
  116.   /* Lock count is zero, close library */
  117.   CloseLibrary(GadToolsBase);
  118.  
  119.   /* Reset library base pointer */
  120.   GadToolsBase = NULL;
  121.  }
  122. }
  123.  
  124. /* Free dock menu */
  125. #undef  DEBUGFUNCTION
  126. #define DEBUGFUNCTION FreeDockMenu
  127. static void FreeDockMenu(struct DockClassData *dcd)
  128. {
  129.  DOCKCLASS_LOG(LOG0(Freeing menu))
  130.  
  131.  FreeMenus(dcd->dcd_Menu);
  132.  FreeVisualInfo(dcd->dcd_VisualInfo);
  133.  ReleaseGadTools();
  134. }
  135.  
  136. /* Create dock menu */
  137. #undef  DEBUGFUNCTION
  138. #define DEBUGFUNCTION CreateDockMenu
  139. static BOOL CreateDockMenu(struct DockClassData *dcd, struct Screen *s)
  140. {
  141.  BOOL rc = FALSE;
  142.  
  143.  DOCKCLASS_LOG(LOG0(Entry))
  144.  
  145.  /* Lock GadTools */
  146.  if (LockGadTools()) {
  147.  
  148.   DOCKCLASS_LOG(LOG0(GadTools locked))
  149.  
  150.   /* Get visual info */
  151.   if (dcd->dcd_VisualInfo = GetVisualInfoA(s, NULL)) {
  152.  
  153.    DOCKCLASS_LOG(LOG1(VisualInfo, "0x%08lx", dcd->dcd_VisualInfo))
  154.  
  155.    /* Create menus */
  156.    if (dcd->dcd_Menu = CreateMenusA(DockMenu, CreateMenusTags)) {
  157.  
  158.     DOCKCLASS_LOG(LOG1(Menu, "0x%08lx", dcd->dcd_Menu))
  159.  
  160.     /* Layout menu */
  161.     if (LayoutMenusA(dcd->dcd_Menu, dcd->dcd_VisualInfo, LayoutMenusTags)) {
  162.  
  163.      DOCKCLASS_LOG(LOG0(Menus OK))
  164.  
  165.      /* All OK */
  166.      rc = TRUE;
  167.  
  168.     } else
  169.  
  170.      /* Couldn't layout menus */
  171.      FreeMenus(dcd->dcd_Menu);
  172.    }
  173.  
  174.    /* Error? Free visual info */
  175.    if (rc == FALSE) FreeVisualInfo(dcd->dcd_VisualInfo);
  176.   }
  177.  
  178.   /* Error? Unlock GadTools*/
  179.   if (rc == FALSE) ReleaseGadTools();
  180.  }
  181.  
  182.  DOCKCLASS_LOG(LOG1(Result, "%ld", rc))
  183.  
  184.  return(rc);
  185. }
  186.  
  187. /* Close dock window */
  188. #undef  DEBUGFUNCTION
  189. #define DEBUGFUNCTION CloseDockWindow
  190. static void CloseDockWindow(Object *obj, struct DockClassData *dcd)
  191. {
  192.  DOCKCLASS_LOG(LOG0(Entry))
  193.  
  194.  /* Window open? */
  195.  if (dcd->dcd_Window) {
  196.  
  197.   DOCKCLASS_LOG(LOG0(Closing window))
  198.  
  199.   /* AppWindow? */
  200.   if (dcd->dcd_AppWindow) DeleteAppWindow(dcd->dcd_AppWindow, obj);
  201.  
  202.   /* Menu attached? */
  203.   if (dcd->dcd_Menu) {
  204.  
  205.    /* Remove menu strip from window */
  206.    ClearMenuStrip(dcd->dcd_Window);
  207.  
  208.    /* Free menu */
  209.    FreeDockMenu(dcd);
  210.   }
  211.  
  212.   /* Remove dock gadget */
  213.   RemoveGList(dcd->dcd_Window, (struct Gadget *) dcd->dcd_Gadget, 1);
  214.  
  215.   /* Sticky bit set? */
  216.   if ((dcd->dcd_Flags & DATA_DOCKF_STICKY) == 0) {
  217.  
  218.    /* No, store new window position */
  219.    dcd->dcd_LeftEdge = dcd->dcd_Window->LeftEdge;
  220.    dcd->dcd_TopEdge  = dcd->dcd_Window->TopEdge;
  221.   }
  222.  
  223.   /* Close window */
  224.   SafeCloseWindow(dcd->dcd_Window);
  225.   dcd->dcd_Window = NULL;
  226.  
  227.   /* Delete dock gadget */
  228.   DisposeObject(dcd->dcd_Gadget);
  229.  
  230.   /* Free font */
  231.   if (dcd->dcd_Font) CloseFont(dcd->dcd_Font);
  232.  }
  233. }
  234.  
  235. /* Create dock gadget */
  236. #undef  DEBUGFUNCTION
  237. #define DEBUGFUNCTION CreateDock
  238. static Object *CreateDock(struct TMHandle *tmh, struct DockClassData *dcd,
  239.                           struct Screen *s, ULONG x, ULONG y)
  240. {
  241.  Object *g = NULL;
  242.  
  243.  DOCKCLASS_LOG(LOG2(Arguments, "X %ld Y %ld", x, y))
  244.  
  245.  /* Clear font pointer */
  246.  dcd->dcd_Font = NULL;
  247.  
  248.  /* Font specified? */
  249.  if (dcd->dcd_TextAttr.ta_Name) {
  250.   struct Library *DiskfontBase;
  251.  
  252.   DOCKCLASS_LOG(LOG0(Load Font))
  253.  
  254.   /* Open diskfont.library */
  255.   if (DiskfontBase = OpenLibrary("diskfont.library", 39)) {
  256.  
  257.    DOCKCLASS_LOG(LOG1(DiskfontBase, "0x%08lx", DiskfontBase))
  258.  
  259.    /* Open disk based font */
  260.    dcd->dcd_Font = OpenDiskFont(&dcd->dcd_TextAttr);
  261.  
  262.    CloseLibrary(DiskfontBase);
  263.   }
  264.  
  265.  } else
  266.  
  267.   /* No, get screen default font */
  268.   dcd->dcd_Font = OpenFont(s->Font);
  269.  
  270.  /* Font opened? */
  271.  if (dcd->dcd_Font) {
  272.  
  273.   DOCKCLASS_LOG(LOG1(Font, "0x%08lx", dcd->dcd_Font))
  274.  
  275.   /* Create group object */
  276.   if (g = NewObject(ToolManagerGroupClass, NULL, GA_Left,      x,
  277.                                                  GA_Top,       y,
  278.                                                  GA_RelVerify, TRUE,
  279.                                                  TAG_DONE)) {
  280.    struct DockEntry *de     = (struct DockEntry *) GetHead(&dcd->dcd_Entries);
  281.    BOOL              images = (dcd->dcd_Flags & DATA_DOCKF_IMAGES) != 0;
  282.    BOOL              text   = (dcd->dcd_Flags & DATA_DOCKF_TEXT)   != 0;
  283.  
  284.    DOCKCLASS_LOG(LOG1(Group, "0x%08lx", g))
  285.  
  286.    /* Scan entries list */
  287.    while (de) {
  288.     Object *b;
  289.  
  290.     /* Create button gadget */
  291.     if (b = NewObject(ToolManagerButtonClass, NULL,
  292.                        TMA_TMHandle, tmh,
  293.                        TMA_Entry,    &de->de_Data,
  294.                        TMA_Screen,   s,
  295.                        TMA_Font,     dcd->dcd_Font,
  296.                        TMA_Images,   images,
  297.                        TMA_Text,     text,
  298.                        TAG_DONE)) {
  299.  
  300.      DOCKCLASS_LOG(LOG1(Button, "0x%08lx", b))
  301.  
  302.      /* Add button to group */
  303.      DoMethod(g, OM_ADDMEMBER, b);
  304.     }
  305.  
  306.     /* Next entry */
  307.     de = (struct DockEntry *) GetSucc((struct MinNode *) de);
  308.    }
  309.  
  310.    /* Layout group */
  311.    if (DoMethod(g, TMM_Layout, dcd->dcd_Columns) == 0) {
  312.  
  313.     /* Layout failed, dispose group */
  314.     DisposeObject(g);
  315.  
  316.     /* Return failure code */
  317.     g = NULL;
  318.  
  319.    } else {
  320.  
  321.     /* Initialize rest of data */
  322.     dcd->dcd_Seconds = 0;
  323.     dcd->dcd_Micros  = 0;
  324.    }
  325.   }
  326.  
  327.   /* Free font if error */
  328.   if (g == NULL) CloseFont(dcd->dcd_Font);
  329.  }
  330.  
  331.  return(g);
  332. }
  333.  
  334. /* Open dock window */
  335. #undef  DEBUGFUNCTION
  336. #define DEBUGFUNCTION OpenDockWindow
  337. static void OpenDockWindow(Object *obj, struct DockClassData *dcd, BOOL beep)
  338. {
  339.  struct Screen *s;
  340.  BOOL           error = TRUE;
  341.  
  342.  /* Open on frontmost public screen? */
  343.  if (dcd->dcd_Flags & DATA_DOCKF_FRONTMOST) {
  344.   ULONG lock;
  345.  
  346.   /* Avoid race conditions */
  347.   Forbid();
  348.  
  349.   /* Lock IntuitionBase */
  350.   lock = LockIBase(0);
  351.  
  352.   /* Get active screen */
  353.   if (s = ((struct IntuitionBase *) IntuitionBase)->ActiveScreen) {
  354.    ULONG type = s->Flags & SCREENTYPE;
  355.  
  356.    DOCKCLASS_LOG(LOG3(ActiveScreen, "0x%08lx Flags 0x%08lx Type 0x%08lx",
  357.                       s, s->Flags, type))
  358.  
  359.    /* Found a public screen? */
  360.    if ((type != WBENCHSCREEN) && (type != PUBLICSCREEN))
  361.  
  362.     /* No! Clear pointer again */
  363.     s = NULL;
  364.   }
  365.  
  366.   /* Unlock IntuitionBase */
  367.   UnlockIBase(lock);
  368.  
  369.   /* Lock public screen */
  370.   if (s) {
  371.    struct List *slist;
  372.  
  373.    /* Get a pointer to the public screen list */
  374.    if (slist = LockPubScreenList()) {
  375.     struct PubScreenNode *snode = (struct PubScreenNode *)
  376.                                    GetHead((struct MinList *) slist);
  377.     UBYTE                 buf[MAXPUBSCREENNAME + 1];
  378.  
  379.     DOCKCLASS_LOG(LOG1(PubScreenList, "0x%08lx", slist))
  380.  
  381.     /* Scan public scren list */
  382.     while (snode) {
  383.  
  384.      DOCKCLASS_LOG(LOG1(Next PubScreen, "%s", snode->psn_Node.ln_Name))
  385.  
  386.      /* Does this node point to our screen? */
  387.      if (snode->psn_Screen == s) {
  388.  
  389.       /* Yes. Copy screen name and leave loop */
  390.       strcpy(buf, snode->psn_Node.ln_Name);
  391.       break;
  392.      }
  393.  
  394.      /* get a pointer to next node */
  395.      snode = (struct PubScreenNode *) GetSucc((struct MinNode *) snode);
  396.     }
  397.  
  398.     /* Release public screen list */
  399.     UnlockPubScreenList();
  400.  
  401.     DOCKCLASS_LOG(LOG1(PubScreenNode, "0x%08lx", snode))
  402.  
  403.     /* Public screen node valid? */
  404.     if (snode)
  405.  
  406.      /* Yes, lock public screen */
  407.      s = LockPubScreen(buf);
  408.  
  409.     else
  410.  
  411.      /* No, clear screen pointer */
  412.      s = NULL;
  413.  
  414.    } else
  415.  
  416.     /* No public screens??? */
  417.     s = NULL;
  418.   }
  419.  
  420.   /* OK, we have a screen now */
  421.   Permit();
  422.  
  423.  } else
  424.  
  425.   /* No, just lock public screen */
  426.   s = LockPubScreen(dcd->dcd_PubScreen);
  427.  
  428.  /* Public screen valid? */
  429.  if (s) {
  430.   struct TMHandle *tmh;
  431.   ULONG            gx;
  432.   ULONG            gy;
  433.   BOOL             border = (dcd->dcd_Flags & DATA_DOCKF_BORDER) != 0;
  434.  
  435.   DOCKCLASS_LOG(LOG1(Screen, "0x%08lx", s))
  436.  
  437.   /* Get correct gadget offsets */
  438.   if (border) {
  439.  
  440.    /* Correct for window borders */
  441.    gx = s->WBorLeft + 1;
  442.    gy = s->WBorTop  + s->Font->ta_YSize + 2;
  443.  
  444.   } else {
  445.  
  446.    /* No border, no offset */
  447.    gx = 0;
  448.    gy = 0;
  449.   }
  450.  
  451.   /* Get TMHandle */
  452.   GetAttr(TMA_TMHandle, obj, (ULONG *) &tmh);
  453.  
  454.   /* Create dock gadget */
  455.   if (dcd->dcd_Gadget = CreateDock(tmh, dcd, s, gx, gy)) {
  456.    char  *name;
  457.    ULONG  wx;
  458.    ULONG  wy;
  459.  
  460.    /* Get name */
  461.    GetAttr(TMA_ObjectName, obj, (ULONG *) &name);
  462.  
  463.    /* Centered window? */
  464.    if (dcd->dcd_Flags & DATA_DOCKF_CENTERED) {
  465.  
  466.     /* Centering: X = MouseX - width/2 - LeftBorder */
  467.     wx = s->MouseX - ((struct Gadget *) dcd->dcd_Gadget)->Width  / 2 - gx;
  468.     wy = s->MouseY - ((struct Gadget *) dcd->dcd_Gadget)->Height / 2 - gy;
  469.  
  470.    /* Not centered */
  471.    } else {
  472.     wx = dcd->dcd_LeftEdge;
  473.     wy = dcd->dcd_TopEdge;
  474.    }
  475.  
  476.    /* Clear menu pointer */
  477.    dcd->dcd_Menu = NULL;
  478.  
  479.    /* Menu flag not set? Otherwise create menus */
  480.    if (((dcd->dcd_Flags & DATA_DOCKF_MENU) == 0) || CreateDockMenu(dcd, s)) {
  481.  
  482.     DOCKCLASS_LOG(LOG1(Menu, "0x%08lx", dcd->dcd_Menu))
  483.  
  484.     /* Open window */
  485.     if (dcd->dcd_Window = OpenWindowTags(NULL,
  486.          WA_Left,         wx,
  487.          WA_Top,          wy,
  488.          WA_InnerWidth,
  489.                 ((struct Gadget *) dcd->dcd_Gadget)->Width  + (border ? 2 : 0),
  490.          WA_InnerHeight,
  491.                 ((struct Gadget *) dcd->dcd_Gadget)->Height + (border ? 2 : 0),
  492.          WA_Title,        border ? name : NULL,
  493.          WA_Borderless,   !border,
  494.          WA_CloseGadget,  border,
  495.          WA_DragBar,      border,
  496.          WA_DepthGadget,  border,
  497.          WA_PubScreen,    s,
  498.          WA_AutoAdjust,   TRUE,
  499.          WA_NewLookMenus, TRUE,
  500.          WA_IDCMP,        0,
  501.          TAG_DONE)) {
  502.  
  503.      DOCKCLASS_LOG(LOG1(Window, "0x%08lx", dcd->dcd_Window))
  504.  
  505.      /* Backdrop flag set? */
  506.      if (dcd->dcd_Flags & DATA_DOCKF_BACKDROP) WindowToBack(dcd->dcd_Window);
  507.  
  508.      /* Attach and activate IDCMP */
  509.      if (AttachIDCMP(obj, dcd->dcd_Window, IDCMP_GADGETUP | IDCMP_MENUPICK |
  510.                                            IDCMP_CLOSEWINDOW |
  511.                                            IDCMP_VANILLAKEY)) {
  512.  
  513.       DOCKCLASS_LOG(LOG0(Window active))
  514.  
  515.       /* Add gadget */
  516.       AddGList(dcd->dcd_Window, (struct Gadget *) dcd->dcd_Gadget, (UWORD) -1,
  517.                1, NULL);
  518.       RefreshGList((struct Gadget *) dcd->dcd_Gadget, dcd->dcd_Window, NULL,
  519.                    1);
  520.  
  521.       /* Add menu */
  522.       if (dcd->dcd_Menu) SetMenuStrip(dcd->dcd_Window, dcd->dcd_Menu);
  523.  
  524.       /* Clear AppWindow pointer */
  525.       dcd->dcd_AppWindow = NULL;
  526.  
  527.       /* On Workbench screen? */
  528.       if ((s->Flags & SCREENTYPE) == WBENCHSCREEN)
  529.  
  530.        /* Yes, activate AppWindow */
  531.        dcd->dcd_AppWindow = CreateAppWindow(obj, dcd->dcd_Window);
  532.  
  533.       DOCKCLASS_LOG(LOG1(AppWindow, "0x%08lx", dcd->dcd_AppWindow))
  534.  
  535.       /* Dock window has been opened */
  536.       error = FALSE;
  537.  
  538.       DOCKCLASS_LOG(LOG0(Gadget attached))
  539.      }
  540.  
  541.      /* Close window if error */
  542.      if (error) {
  543.       SafeCloseWindow(dcd->dcd_Window);
  544.       dcd->dcd_Window = NULL;
  545.      }
  546.     }
  547.  
  548.     /* Free dock menu if error */
  549.     if (dcd->dcd_Menu && error) FreeDockMenu(dcd);
  550.    }
  551.  
  552.    /* Dispose dock gadget if error */
  553.    if (error) DisposeObject(dcd->dcd_Gadget);
  554.   }
  555.  
  556.   /* Unlock screen */
  557.   UnlockPubScreen(NULL, s);
  558.  }
  559.  
  560.  /* Error? */
  561.  if (error)
  562.  
  563.   /* beep allowed? */
  564.   if (beep)
  565.  
  566.    /* Flash screens! */
  567.    DisplayBeep(NULL);
  568.  
  569.   else
  570.  
  571.    /* No, but mark dock window for re-opening when screen is available */
  572.    dcd->dcd_Flags |= DOCKF_REOPEN;
  573. }
  574.  
  575. /* Dock class method: OM_NEW */
  576. #undef  DEBUGFUNCTION
  577. #define DEBUGFUNCTION DockClassNew
  578. static ULONG DockClassNew(Class *cl, Object *obj, struct opSet *ops)
  579. {
  580.  DOCKCLASS_LOG((LOG1(Tags, "0x%08lx", ops->ops_AttrList),
  581.                 PrintTagList(ops->ops_AttrList)))
  582.  
  583.  /* Call SuperClass */
  584.  if (obj = (Object *) DoSuperMethodA(cl, obj, (Msg) ops)) {
  585.   struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  586.  
  587.   /* Initialize instance data */
  588.   dcd->dcd_Flags            = 0;
  589.   dcd->dcd_LeftEdge         = 0;
  590.   dcd->dcd_TopEdge          = 0;
  591.   dcd->dcd_Columns          = 0;
  592.   dcd->dcd_TextAttr.ta_Name = NULL;
  593.   dcd->dcd_PubScreen        = NULL;
  594.   dcd->dcd_HotKey           = NULL;
  595.   dcd->dcd_Window           = NULL;
  596.  
  597.   /* Initialize dock entries list */
  598.   NewList((struct List *) &dcd->dcd_Entries);
  599.  
  600.   /* We need screen notifications */
  601.   LockScreenNotify();
  602.  }
  603.  
  604.  return((ULONG) obj);
  605. }
  606.  
  607. /* Dock class method: OM_DISPOSE */
  608. #undef  DEBUGFUNCTION
  609. #define DEBUGFUNCTION DockClassDispose
  610. static ULONG DockClassDispose(Class *cl, Object *obj, Msg msg)
  611. {
  612.  struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  613.  
  614.  DOCKCLASS_LOG(LOG0(Disposing))
  615.  
  616.  /* We don't need screen notifications anymore */
  617.  ReleaseScreenNotify();
  618.  
  619.  /* Close dock */
  620.  CloseDockWindow(obj, dcd);
  621.  
  622.  /* Free dock entries */
  623.  {
  624.   struct DockEntry *de;
  625.  
  626.   /* Remove entry from head of list */
  627.   while (de = (struct DockEntry *) RemHead((struct List *) &dcd->dcd_Entries))
  628.  
  629.    /* Free entry */
  630.    FreeMemory(de, sizeof(struct DockEntry));
  631.  }
  632.  
  633.  /* Hotkey allocated? */
  634.  if (dcd->dcd_HotKey) SafeDeleteCxObjAll(dcd->dcd_HotKey, obj);
  635.  
  636.  /* Free IFF data */
  637.  if (dcd->dcd_Flags & IFFF_PUBSCREEN) FreeVector(dcd->dcd_PubScreen);
  638.  if (dcd->dcd_Flags & IFFF_FONTNAME)  FreeVector(dcd->dcd_TextAttr.ta_Name);
  639.  
  640.  /* Call SuperClass */
  641.  return(DoSuperMethodA(cl, obj, msg));
  642. }
  643.  
  644. /* Dock class method: TMM_ParseIFF */
  645. #undef  DEBUGFUNCTION
  646. #define DEBUGFUNCTION DockClassParseIFF
  647. static ULONG DockClassParseIFF(Class *cl, Object *obj,
  648.                                struct TMP_ParseIFF *tmppi)
  649. {
  650.  BOOL rc = FALSE;
  651.  
  652.  DOCKCLASS_LOG(LOG1(Handle, "0x%08lx", tmppi->tmppi_IFFHandle))
  653.  
  654.  /* Initialize IFF parser and forward method to SuperClass */
  655.  if ((PropChunks(tmppi->tmppi_IFFHandle, PropChunkTable, PROPCHUNKS) == 0) &&
  656.      (CollectionChunk(tmppi->tmppi_IFFHandle, ID_TMDO, ID_ENTR) == 0) &&
  657.      DoSuperMethodA(cl, obj, (Msg) tmppi)) {
  658.   struct StoredProperty *sp;
  659.  
  660.   DOCKCLASS_LOG(LOG0(FORM TMDO chunk parsed OK))
  661.  
  662.   /* Check for mandatory DATA property */
  663.   if (sp = FindProp(tmppi->tmppi_IFFHandle, ID_TMDO, ID_DATA)) {
  664.    struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  665.    struct DockDATAChunk *ddc = sp->sp_Data;
  666.  
  667.    DOCKCLASS_LOG(LOG4(Data1,
  668.                       "Flags 0x%08lx X %ld Y %ld Cols %ld",
  669.                       ddc->ddc_Standard.sdc_Flags, ddc->ddc_LeftEdge,
  670.                       ddc->ddc_TopEdge, ddc->ddc_Columns))
  671.    DOCKCLASS_LOG(LOG3(Data2,
  672.                       "Font YSize %ld Style 0x%02lx Flags 0x%02lx",
  673.                       ddc->ddc_FontYSize, ddc->ddc_FontStyle,
  674.                       ddc->ddc_FontFlags))
  675.  
  676.    /* Initialize class data */
  677.    dcd->dcd_Flags             = ddc->ddc_Standard.sdc_Flags & DATA_DOCKF_MASK;
  678.    dcd->dcd_LeftEdge          = ddc->ddc_LeftEdge;
  679.    dcd->dcd_TopEdge           = ddc->ddc_TopEdge;
  680.    dcd->dcd_Columns           = ddc->ddc_Columns;
  681.    dcd->dcd_TextAttr.ta_YSize = ddc->ddc_FontYSize;
  682.    dcd->dcd_TextAttr.ta_Style = ddc->ddc_FontStyle;
  683.    dcd->dcd_TextAttr.ta_Flags = ddc->ddc_FontFlags;
  684.  
  685.    /* Duplicate strings and set flags */
  686.    if (dcd->dcd_TextAttr.ta_Name = DuplicateProperty(tmppi->tmppi_IFFHandle,
  687.                                                      ID_TMDO, ID_FONT))
  688.     dcd->dcd_Flags |= IFFF_FONTNAME;
  689.    if (dcd->dcd_PubScreen        = DuplicateProperty(tmppi->tmppi_IFFHandle,
  690.                                                      ID_TMDO, ID_PSCR))
  691.     dcd->dcd_Flags |= IFFF_PUBSCREEN;
  692.  
  693.    /* HotKey specified? */
  694.    if (sp = FindProp(tmppi->tmppi_IFFHandle, ID_TMDO, ID_HKEY))
  695.  
  696.     /* Yes, reate Hotkey */
  697.     dcd->dcd_HotKey = CreateHotKey(sp->sp_Data, obj);
  698.  
  699.    /* Build dock entries list */
  700.    {
  701.     struct CollectionItem *ci;
  702.  
  703.     /* Any entries found? */
  704.     if (ci = FindCollection(tmppi->tmppi_IFFHandle, ID_TMDO, ID_ENTR)) {
  705.      struct DockEntry *de;
  706.  
  707.      DOCKCLASS_LOG(LOG1(Collection, "0x%08lx", ci))
  708.  
  709.      /* Scan collection item list */
  710.      while (ci) {
  711.  
  712.       DOCKCLASS_LOG(LOG1(Next, "0x%08lx", ci))
  713.  
  714.       /* Allocate memory for next entry */
  715.       if (de = GetMemory(sizeof(struct DockEntry))) {
  716.  
  717.        /* Copy data */
  718.        de->de_Data = *((struct DockEntryChunk *) ci->ci_Data);
  719.  
  720.        /* Insert entry at the head of the list */
  721.        AddHead((struct List *) &dcd->dcd_Entries, (struct Node *) de);
  722.  
  723.       } else
  724.  
  725.        /* No memory, leave loop */
  726.        break;
  727.  
  728.       /* Next collection item */
  729.       ci = ci->ci_Next;
  730.      }
  731.     }
  732.    }
  733.  
  734.    /* Dock active? */
  735.    if (dcd->dcd_Flags & DATA_DOCKF_ACTIVATED) OpenDockWindow(obj, dcd, FALSE);
  736.  
  737.    /* Configuration data parsed */
  738.    rc = TRUE;
  739.   }
  740.  }
  741.  
  742.  DOCKCLASS_LOG(LOG1(Result, "%ld", rc))
  743.  
  744.  return(rc);
  745. }
  746.  
  747. /* Dock class method: TMM_ParseTags */
  748. #undef  DEBUGFUNCTION
  749. #define DEBUGFUNCTION DockClassParseTags
  750. static ULONG DockClassParseTags(Class *cl, Object *obj,
  751.                                 struct TMP_ParseTags *tmppt)
  752. {
  753.  struct DockClassData *dcd    = TYPED_INST_DATA(cl, obj);
  754.  struct TagItem       *tstate = tmppt->tmppt_Tags;
  755.  struct TagItem       *ti;
  756.  struct TMHandle      *tmh;
  757.  BOOL                  rc     = TRUE;
  758.  
  759.  DOCKCLASS_LOG((LOG1(Tags, "0x%08lx", tmppt->tmppt_Tags),
  760.                 PrintTagList(tmppt->tmppt_Tags)))
  761.  
  762.  /* Remove old dock first */
  763.  CloseDockWindow(obj, dcd);
  764.  
  765.  /* Get TMHandle */
  766.  GetAttr(TMA_TMHandle, obj, (ULONG *) &tmh);
  767.  
  768.  /* Scan tag list */
  769.  while (rc && (ti = NextTagItem(&tstate)))
  770.  
  771.   /* Which tag? */
  772.   switch (ti->ti_Tag) {
  773.    case TMOP_HotKey:
  774.     /* Free old hotkey */
  775.     if (dcd->dcd_HotKey) SafeDeleteCxObjAll(dcd->dcd_HotKey, obj);
  776.  
  777.     /* String valid? */
  778.     if (ti->ti_Data)
  779.  
  780.      /* Yes, create new hotkey */
  781.      rc = (dcd->dcd_HotKey = CreateHotKey((char *) ti->ti_Data, obj)) != NULL;
  782.  
  783.     else
  784.  
  785.      /* Hotkey cleared */
  786.      dcd->dcd_HotKey = NULL;
  787.  
  788.     break;
  789.  
  790.    case TMOP_PubScreen:
  791.     dcd->dcd_PubScreen = (char *) ti->ti_Data;
  792.     break;
  793.  
  794.    case TMOP_LeftEdge:
  795.     dcd->dcd_LeftEdge = ti->ti_Data;
  796.     break;
  797.  
  798.    case TMOP_TopEdge:
  799.     dcd->dcd_TopEdge = ti->ti_Data;
  800.     break;
  801.  
  802.    case TMOP_Columns:
  803.     dcd->dcd_Columns = ti->ti_Data;
  804.     break;
  805.  
  806.    case TMOP_Font:
  807.     dcd->dcd_TextAttr = *((struct TextAttr *) ti->ti_Data);
  808.     break;
  809.  
  810.    case TMOP_Tool:
  811.     /* Tool valid? */
  812.     if (ti->ti_Data) {
  813.      struct DockEntry *de;
  814.  
  815.      /* Yes, get memory for dock entry */
  816.      if (de = GetMemory(sizeof(struct DockEntry))) {
  817.       char   **names  = (char **) ti->ti_Data;
  818.       Object  *newobj;
  819.  
  820.       /* Get Exec object */
  821.       if (names[0] && (newobj = FindTypedNamedTMObject(tmh, names[0],
  822.                                                        TMOBJTYPE_EXEC)))
  823.  
  824.        /* Get object ID */
  825.        GetAttr(TMA_ObjectID, newobj, &de->de_Data.dec_ExecObject);
  826.  
  827.       /* Get Image object */
  828.       if (names[1] && (newobj = FindTypedNamedTMObject(tmh, names[1],
  829.                                                        TMOBJTYPE_IMAGE)))
  830.  
  831.        /* Get object ID */
  832.        GetAttr(TMA_ObjectID, newobj, &de->de_Data.dec_ImageObject);
  833.  
  834.       /* Get Exec object */
  835.       if (names[2] && (newobj = FindTypedNamedTMObject(tmh, names[2],
  836.                                                        TMOBJTYPE_SOUND)))
  837.  
  838.        /* Get object ID */
  839.        GetAttr(TMA_ObjectID, newobj, &de->de_Data.dec_SoundObject);
  840.  
  841.       /* Insert entry at the head of the list */
  842.       AddHead((struct List *) &dcd->dcd_Entries, (struct Node *) de);
  843.  
  844.      } else
  845.  
  846.       /* Error */
  847.       rc = FALSE;
  848.     }
  849.     break;
  850.   }
  851.  
  852.  /* Set flags */
  853.  if (rc) dcd->dcd_Flags = PackBoolTags(dcd->dcd_Flags, tmppt->tmppt_Tags,
  854.                                        TagsToFlags);
  855.  
  856.  /* Open dock? */
  857.  if (rc && (dcd->dcd_Window == NULL) &&
  858.      (dcd->dcd_Flags & DATA_DOCKF_ACTIVATED))
  859.  
  860.   /* Yes */
  861.   OpenDockWindow(obj, dcd, FALSE);
  862.  
  863.  DOCKCLASS_LOG(LOG1(Result, "%ld", rc))
  864.  
  865.  return(rc);
  866. }
  867.  
  868. /* Activate one dock entry */
  869. #undef  DEBUGFUNCTION
  870. #define DEBUGFUNCTION ActivateDockEntry
  871. static BOOL ActivateDockEntry(struct DockClassData *dcd, ULONG id, ULONG data)
  872. {
  873.  BOOL rc;
  874.  
  875.  DOCKCLASS_LOG(LOG0(Entry))
  876.  
  877.  /* We are active now, please don't close the window */
  878.  dcd->dcd_Flags |= DOCKF_DEFERCLOSE;
  879.  
  880.  /* Send message do object */
  881.  DoMethod(dcd->dcd_Gadget, id, data);
  882.  
  883.  /* Popup dock or defered close flag cleared? */
  884.  if ((dcd->dcd_Flags & DATA_DOCKF_POPUP) ||
  885.      ((dcd->dcd_Flags & DOCKF_DEFERCLOSE) == 0))
  886.  
  887.   /* Close dock window */
  888.   rc = TRUE;
  889.  
  890.  else {
  891.  
  892.   /* Reset defered close flag */
  893.   dcd->dcd_Flags &= ~DOCKF_DEFERCLOSE;
  894.  
  895.   /* Window should NOT be closed */
  896.   rc = FALSE;
  897.  }
  898.  
  899.  DOCKCLASS_LOG(LOG1(Result, "%ld", rc))
  900.  
  901.  /* Return TRUE if the window should be closed */
  902.  return(rc);
  903. }
  904.  
  905.  
  906. /* Exec class method: TMM_Activate */
  907. #undef  DEBUGFUNCTION
  908. #define DEBUGFUNCTION DockClassActivate
  909. static ULONG DockClassActivate(Class *cl, Object *obj,
  910.                                struct TMP_Activate *tmpa)
  911. {
  912.  struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  913.  
  914.  DOCKCLASS_LOG(LOG1(Data, "0x%08lx", tmpa->tmpa_Data))
  915.  
  916.  /* Data valid? */
  917.  if (tmpa->tmpa_Data) {
  918.  
  919.   /* Activate dock entry */
  920.   if (ActivateDockEntry(dcd, TMM_AppEvent, (ULONG) tmpa->tmpa_Data))
  921.  
  922.    /* Please close window */
  923.    CloseDockWindow(obj, dcd);
  924.  
  925.  /* No data, user pressed hotkey. Dock window open? */
  926.  } else if (dcd->dcd_Window)
  927.  
  928.   /* Close defered? */
  929.   if (dcd->dcd_Flags & DOCKF_DEFERCLOSE)
  930.  
  931.    /* Yes, reset flag */
  932.    dcd->dcd_Flags &= ~DOCKF_DEFERCLOSE;
  933.  
  934.   else
  935.  
  936.    /* No, close window */
  937.    CloseDockWindow(obj, dcd);
  938.  
  939.  /* Dock window is not open, open it */
  940.  else OpenDockWindow(obj, dcd, TRUE);
  941.  
  942.  /* Return 1 to indicate that the method is implemented */
  943.  return(1);
  944. }
  945.  
  946. /* Dock class method: TMM_IDCMPEvent */
  947. #undef  DEBUGFUNCTION
  948. #define DEBUGFUNCTION DockClassIDCMPEvent
  949. static ULONG DockClassIDCMPEvent(Class *cl, Object *obj,
  950.                                  struct TMP_IDCMPEvent *tmpie)
  951. {
  952.  struct DockClassData *dcd   = TYPED_INST_DATA(cl, obj);
  953.  BOOL                  close = FALSE;
  954.  
  955.  /* Which event? */
  956.  switch (tmpie->tmpie_Message->Class) {
  957.  
  958.   case IDCMP_GADGETUP: {
  959.     struct IntuiMessage *msg = tmpie->tmpie_Message;
  960.  
  961.     /* Check double click time */
  962.     if (DoubleClick(dcd->dcd_Seconds, dcd->dcd_Micros,
  963.                     msg->Seconds,     msg->Micros) == FALSE)
  964.  
  965.      /* Not a double click -> Activate dock entry */
  966.      close = ActivateDockEntry(dcd, TMM_GadgetUp, msg->Code);
  967.  
  968.     /* Save time */
  969.     dcd->dcd_Seconds = msg->Seconds;
  970.     dcd->dcd_Micros  = msg->Micros;
  971.    }
  972.    break;
  973.  
  974.   case IDCMP_MENUPICK: {
  975.     USHORT menunum = tmpie->tmpie_Message->Code;
  976.  
  977.     /* Scan all menu events */
  978.     while (menunum != MENUNULL) {
  979.      struct MenuItem *menuitem = ItemAddress(dcd->dcd_Menu, menunum);
  980.  
  981.      DOCKCLASS_LOG(LOG2(Menu event, "Num 0x%04lx Item 0x%08lx", menunum,
  982.                         menuitem))
  983.  
  984.      /* Which menu selected? */
  985.      switch (GTMENUITEM_USERDATA(menuitem)) {
  986.       case MENU_CLOSE: close = TRUE;       break;
  987.       case MENU_PREFS: StartPreferences(); break;
  988.       case MENU_QUIT:  KillToolManager();  break;
  989.      }
  990.  
  991.      /* Get next menu event */
  992.      menunum = menuitem->NextSelect;
  993.     }
  994.    }
  995.    break;
  996.  
  997.   case IDCMP_CLOSEWINDOW:
  998.    close = TRUE;
  999.    break;
  1000.  
  1001.   case IDCMP_VANILLAKEY:
  1002.    /* Which key was pressed? */
  1003.    switch (tmpie->tmpie_Message->Code) {
  1004.     case 0x03: /* CTRL-C */
  1005.     case 0x1B: /* ESC    */
  1006.      close = TRUE;
  1007.      break;
  1008.    }
  1009.    break;
  1010.  }
  1011.  
  1012.  /* Reply message */
  1013.  ReplyMsg((struct Message *) tmpie->tmpie_Message);
  1014.  
  1015.  /* Close window? */
  1016.  if (close) CloseDockWindow(obj, dcd);
  1017.  
  1018.  /* Return 1 to indicate that the method is implemented */
  1019.  return(1);
  1020. }
  1021.  
  1022. /* Dock class method: TMM_ScreenOpen */
  1023. #undef  DEBUGFUNCTION
  1024. #define DEBUGFUNCTION DockClassScreenOpen
  1025. static ULONG DockClassScreenOpen(Class *cl, Object *obj,
  1026.                                  struct TMP_ScreenOpen *tmpso)
  1027. {
  1028.  struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  1029.  
  1030.  /* Dock window marked for re-opening? */
  1031.  if ((dcd->dcd_Flags & DOCKF_REOPEN) &&
  1032.  
  1033.  /* Public screen name specified for this dock? */
  1034.      (dcd->dcd_PubScreen != NULL) &&
  1035.  
  1036.  /* Does public screen name match? */
  1037.      (stricmp(dcd->dcd_PubScreen, tmpso->tmpso_Name) == 0)) {
  1038.  
  1039.   /* Yes, open dock window */
  1040.   OpenDockWindow(obj, dcd, TRUE);
  1041.  
  1042.   /* Clear re-open flag */
  1043.   dcd->dcd_Flags &= ~DOCKF_REOPEN;
  1044.  }
  1045.  
  1046.  /* Return 1 to indicate that the method is implemented */
  1047.  return(1);
  1048. }
  1049.  
  1050. /* Dock class method: TMM_ScreenClose */
  1051. #undef  DEBUGFUNCTION
  1052. #define DEBUGFUNCTION DockClassScreenClose
  1053. static ULONG DockClassScreenClose(Class *cl, Object *obj,
  1054.                                   struct TMP_ScreenClose *tmpsc)
  1055. {
  1056.  struct DockClassData *dcd = TYPED_INST_DATA(cl, obj);
  1057.  
  1058.  /* Is window open and does the screen match? */
  1059.  if (dcd->dcd_Window && (dcd->dcd_Window->WScreen == tmpsc->tmpsc_Screen)) {
  1060.  
  1061.   /* Yes, close dock window */
  1062.   CloseDockWindow(obj, dcd);
  1063.  
  1064.   /* Mark dock window for re-opening when screen is available again */
  1065.   dcd->dcd_Flags |= DOCKF_REOPEN;
  1066.  }
  1067.  
  1068.  /* Return 1 to indicate that the method is implemented */
  1069.  return(1);
  1070. }
  1071.  
  1072. /* Dock class dispatcher */
  1073. #undef  DEBUGFUNCTION
  1074. #define DEBUGFUNCTION DockClassDispatcher
  1075. static __geta4 ULONG DockClassDispatcher(__A0 Class *cl, __A2 Object *obj,
  1076.                                          __A1 Msg msg)
  1077. {
  1078.  ULONG rc;
  1079.  
  1080.  DOCKCLASS_LOG(LOG3(Arguments, "Class 0x%08lx Object 0x%08lx Msg 0x%08lx",
  1081.                     cl, obj, msg))
  1082.  
  1083.  switch(msg->MethodID) {
  1084.   /* BOOPSI methods */
  1085.   case OM_NEW:
  1086.    rc = DockClassNew(cl, obj, (struct opSet *) msg);
  1087.    break;
  1088.  
  1089.   case OM_DISPOSE:
  1090.    rc = DockClassDispose(cl, obj, msg);
  1091.    break;
  1092.  
  1093.   /* TM methods */
  1094.   case TMM_ParseIFF:
  1095.    rc = DockClassParseIFF(cl, obj, (struct TMP_ParseIFF *) msg);
  1096.    break;
  1097.  
  1098.   case TMM_ParseTags:
  1099.    rc = DockClassParseTags(cl, obj, (struct TMP_ParseTags *) msg);
  1100.    break;
  1101.  
  1102.   case TMM_Activate:
  1103.    rc = DockClassActivate(cl, obj, (struct TMP_Activate *) msg);
  1104.    break;
  1105.  
  1106.   case TMM_IDCMPEvent:
  1107.    rc = DockClassIDCMPEvent(cl, obj, (struct TMP_IDCMPEvent *) msg);
  1108.    break;
  1109.  
  1110.   case TMM_ScreenOpen:
  1111.    rc = DockClassScreenOpen(cl, obj, (struct TMP_ScreenOpen *) msg);
  1112.    break;
  1113.  
  1114.   case TMM_ScreenClose:
  1115.    rc = DockClassScreenClose(cl, obj, (struct TMP_ScreenClose *) msg);
  1116.    break;
  1117.  
  1118.   /* Unknown method -> delegate to SuperClass */
  1119.   default:
  1120.    rc = DoSuperMethodA(cl, obj, msg);
  1121.    break;
  1122.  }
  1123.  
  1124.  return(rc);
  1125. }
  1126.  
  1127. /* Create Dock class */
  1128. #undef  DEBUGFUNCTION
  1129. #define DEBUGFUNCTION CreateDockClass
  1130. Class *CreateDockClass(Class *superclass)
  1131. {
  1132.  Class *cl;
  1133.  
  1134.  DOCKCLASS_LOG(LOG1(SuperClass, "0x%08lx", superclass))
  1135.  
  1136.  /* Create class */
  1137.  if (cl = MakeClass(NULL, NULL, superclass, sizeof(struct DockClassData), 0)) {
  1138.  
  1139.   /* Set dispatcher */
  1140.   cl->cl_Dispatcher.h_Entry = (ULONG (*)()) DockClassDispatcher;
  1141.  
  1142.   /* Localize strings */
  1143.   DockMenu[0].nm_Label   = TranslateString(
  1144.                                    LOCALE_LIBRARY_DOCK_MENU_TITLE_STR,
  1145.                                    LOCALE_LIBRARY_DOCK_MENU_TITLE);
  1146.   DockMenu[1].nm_Label   = TranslateString(
  1147.                                    LOCALE_LIBRARY_DOCK_MENU_CLOSE_ITEM_STR,
  1148.                                    LOCALE_LIBRARY_DOCK_MENU_CLOSE_ITEM);
  1149.   DockMenu[1].nm_CommKey = TranslateString(
  1150.                                    LOCALE_LIBRARY_DOCK_MENU_CLOSE_SHORTCUT_STR,
  1151.                                    LOCALE_LIBRARY_DOCK_MENU_CLOSE_SHORTCUT);
  1152.   DockMenu[2].nm_Label   = TranslateString(
  1153.                                    LOCALE_LIBRARY_DOCK_MENU_PREFS_ITEM_STR,
  1154.                                    LOCALE_LIBRARY_DOCK_MENU_PREFS_ITEM);
  1155.   DockMenu[2].nm_CommKey = TranslateString(
  1156.                                    LOCALE_LIBRARY_DOCK_MENU_PREFS_SHORTCUT_STR,
  1157.                                    LOCALE_LIBRARY_DOCK_MENU_PREFS_SHORTCUT);
  1158.   DockMenu[3].nm_Label   = TranslateString(
  1159.                                    LOCALE_LIBRARY_DOCK_MENU_QUIT_ITEM_STR,
  1160.                                    LOCALE_LIBRARY_DOCK_MENU_QUIT_ITEM);
  1161.   DockMenu[3].nm_CommKey = TranslateString(
  1162.                                    LOCALE_LIBRARY_DOCK_MENU_QUIT_SHORTCUT_STR,
  1163.                                    LOCALE_LIBRARY_DOCK_MENU_QUIT_SHORTCUT);
  1164.  }
  1165.  
  1166.  DOCKCLASS_LOG(LOG1(Class, "0x%08lx", cl))
  1167.  
  1168.  /* Return pointer to class */
  1169.  return(cl);
  1170. }
  1171.